package cn.omisheep.au.core.filter;

import cn.omisheep.au.core.AuConfig;
import cn.omisheep.au.core.AuValidate;
import cn.omisheep.au.core.JwtHelper;
import cn.omisheep.au.core.RequestStatus;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Slf4j
@WebFilter(filterName = "AuFilter", urlPatterns = "/*")
@SuppressWarnings("all")
public class AuFilter extends OncePerRequestFilter {

    @Autowired
    private AuConfig auConfig;
    @Autowired
    private JwtHelper jwtHelper;
    @Autowired
    private AuValidate auValidate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("authorization");
        if (token != null) { //如果存在jwt，那么解析这个jwt。
            try {
                // 数据读取模块
                Claims claims = jwtHelper.parseToken(token);

                String role = claims.get("role", String.class);

                RequestStatus status = auValidate.validate(request, role);
                if (status.equals(RequestStatus.PERM_EXCEPTION)) {
                    response.getWriter().write(e(1));
                    return;
                } else if (status.equals(RequestStatus.REQUEST_REPEAT)) {
                    response.getWriter().write(e(2));
                    return;
                }
                request.setAttribute("au-info", claims);
            } catch (ExpiredJwtException e) {
                response.getWriter().write(e(3));
                return;
            } catch (SignatureException e) {
                response.getWriter().write(e(4));
                return;
            } catch (MalformedJwtException e) {
                response.getWriter().write(e(5));
                return;
            } catch (Exception e) {
                response.getWriter().write(e(0));
                return;
            }
        } else {
            RequestStatus status = auValidate.validate(request);
            if (status.equals(RequestStatus.PERM_EXCEPTION)) {
                response.getWriter().write(e(1));
                return;
            } else if (status.equals(RequestStatus.REQUEST_REPEAT)) {
                response.getWriter().write(e(2));
                return;
            }
        }
        filterChain.doFilter(request, response);
    }


    @Data
    @AllArgsConstructor
    class ErrorRet {
        private int code;
        private String message;

        public ErrorRet(int code, String message, Object data) {
            this.code = code;
            this.message = message;
        }
    }

    public String e(int i) {
        switch (i) {
            case 1:
                return JSONObject.toJSONString(
                        new ErrorRet(auConfig.getErrorConfig().getPermissionsExceptionCode(), "insufficient permissions")
                );
            case 2:
                return JSONObject.toJSONString(
                        new ErrorRet(auConfig.getErrorConfig().getRequestRepeat(), "request repeat error")
                );
            case 3:
                return JSONObject.toJSONString(
                        new ErrorRet(auConfig.getErrorConfig().getExpiredJwtExceptionCode(), "expired jwt exception")
                );
            case 4:
                return JSONObject.toJSONString(
                        new ErrorRet(auConfig.getErrorConfig().getSignatureExceptionCode(), "signature exception")
                );
            case 5:
                return JSONObject.toJSONString(
                        new ErrorRet(auConfig.getErrorConfig().getMalformedJwtExceptionCode(), "malformed jwt exception")
                );
            default:
                return JSONObject.toJSONString(
                        new ErrorRet(0, "server error")
                );
        }

    }
}

